home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkVisual.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  14KB  |  473 lines

  1. /* 
  2.  * tkVisual.c --
  3.  *
  4.  *    This file contains library procedures for allocating and
  5.  *    freeing visuals and colormaps.  This code is based on a
  6.  *    prototype implementation by Paul Mackerras.
  7.  *
  8.  * Copyright (c) 1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  */
  14.  
  15. static char sccsid[] = "@(#) tkVisual.c 1.12 95/05/09 13:47:42";
  16.  
  17. #include "tkInt.h"
  18. #include "tkPort.h"
  19.  
  20. /*
  21.  * The table below maps from symbolic names for visual classes
  22.  * to the associated X class symbols.
  23.  */
  24.  
  25. typedef struct VisualDictionary {
  26.     char *name;            /* Textual name of class. */
  27.     int minLength;        /* Minimum # characters that must be
  28.                  * specified for an unambiguous match. */
  29.     int class;            /* X symbol for class. */
  30. } VisualDictionary;
  31. static VisualDictionary visualNames[] = {
  32.     {"best",        1,    0},
  33.     {"directcolor",    2,    DirectColor},
  34.     {"grayscale",    1,    GrayScale},
  35.     {"greyscale",    1,    GrayScale},
  36.     {"pseudocolor",    1,    PseudoColor},
  37.     {"staticcolor",    7,    StaticColor},
  38.     {"staticgray",    7,    StaticGray},
  39.     {"staticgrey",    7,    StaticGray},
  40.     {"truecolor",    1,    TrueColor},
  41.     {NULL,        0,    0},
  42. };
  43.  
  44. /*
  45.  * One of the following structures exists for each distinct non-default
  46.  * colormap allocated for a display by Tk_GetColormap.
  47.  */
  48.  
  49. struct TkColormap {
  50.     Colormap colormap;        /* X's identifier for the colormap. */
  51.     Visual *visual;        /* Visual for which colormap was
  52.                  * allocated. */
  53.     int refCount;        /* How many uses of the colormap are still
  54.                  * outstanding (calls to Tk_GetColormap
  55.                  * minus calls to Tk_FreeColormap). */
  56.     int shareable;        /* 0 means this colormap was allocated by
  57.                  * a call to Tk_GetColormap with "new",
  58.                  * implying that the window wants it all
  59.                  * for itself.  1 means that the colormap
  60.                  * was allocated as a default for a particular
  61.                  * visual, so it can be shared. */
  62.     struct TkColormap *nextPtr;    /* Next in list of colormaps for this display,
  63.                  * or NULL for end of list. */
  64. };
  65.  
  66. /*
  67.  *----------------------------------------------------------------------
  68.  *
  69.  * Tk_GetVisual --
  70.  *
  71.  *    Given a string identifying a particular kind of visual, this
  72.  *    procedure returns a visual and depth that matches the specification.
  73.  *
  74.  * Results:
  75.  *    The return value is normally a pointer to a visual.  If an
  76.  *    error occurred in looking up the visual, NULL is returned and
  77.  *    an error message is left in interp->result.  The depth of the
  78.  *    visual is returned to *depthPtr under normal returns.  If
  79.  *    colormapPtr is non-NULL, then this procedure also finds a
  80.  *    suitable colormap for use with the visual in tkwin, and it
  81.  *    returns that colormap in *colormapPtr unless an error occurs.
  82.  *
  83.  * Side effects:
  84.  *    A new colormap may be allocated.
  85.  *
  86.  *----------------------------------------------------------------------
  87.  */
  88.  
  89. Visual *
  90. Tk_GetVisual(interp, tkwin, string, depthPtr, colormapPtr)
  91.     Tcl_Interp *interp;            /* Interpreter to use for error
  92.                      * reporting. */
  93.     Tk_Window tkwin;            /* Window in which visual will be
  94.                      * used. */
  95.     char *string;            /* String describing visual.  See
  96.                      * manual entry for details. */
  97.     int *depthPtr;            /* The depth of the returned visual
  98.                      * is stored here. */
  99.     Colormap *colormapPtr;        /* If non-NULL, then a suitable
  100.                      * colormap for visual is placed here.
  101.                      * This colormap must eventually be
  102.                      * freed by calling Tk_FreeColormap. */
  103. {
  104.     Tk_Window tkwin2;
  105.     XVisualInfo template, *visInfoList, *bestPtr;
  106.     long mask;
  107.     Visual *visual;
  108.     int length, c, numVisuals, prio, bestPrio, i;
  109.     char *p;
  110.     VisualDictionary *dictPtr;
  111.     TkColormap *cmapPtr;
  112.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  113.  
  114.     /*
  115.      * Parse string and set up a template for use in searching for
  116.      * an appropriate visual.
  117.      */
  118.  
  119.     c = string[0];
  120.     if (c == '.') {
  121.     /*
  122.      * The string must be a window name.  If the window is on the
  123.      * same screen as tkwin, then just use its visual.  Otherwise
  124.      * use the information about the visual as a template for the
  125.      * search.
  126.      */
  127.  
  128.     tkwin2 = Tk_NameToWindow(interp, string, tkwin);
  129.     if (tkwin2 == NULL) {
  130.         return NULL;
  131.     }
  132.     visual = Tk_Visual(tkwin2);
  133.     if (Tk_Screen(tkwin) == Tk_Screen(tkwin2)) {
  134.         *depthPtr = Tk_Depth(tkwin2);
  135.         if (colormapPtr != NULL) {
  136.         /*
  137.          * Use the colormap from the other window too (but be sure
  138.          * to increment its reference count if it's one of the ones
  139.          * allocated here).
  140.          */
  141.  
  142.         *colormapPtr = Tk_Colormap(tkwin2);
  143.         for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  144.             cmapPtr = cmapPtr->nextPtr) {
  145.             if (cmapPtr->colormap == *colormapPtr) {
  146.             cmapPtr->refCount += 1;
  147.             break;
  148.             }
  149.         }
  150.         }
  151.         return visual;
  152.     }
  153.     template.depth = Tk_Depth(tkwin2);
  154.     template.class = visual->class;
  155.     template.red_mask = visual->red_mask;
  156.     template.green_mask = visual->green_mask;
  157.     template.blue_mask = visual->blue_mask;
  158.     template.colormap_size = visual->map_entries;
  159.     template.bits_per_rgb = visual->bits_per_rgb;
  160.     mask = VisualDepthMask|VisualClassMask|VisualRedMaskMask
  161.         |VisualGreenMaskMask|VisualBlueMaskMask|VisualColormapSizeMask
  162.         |VisualBitsPerRGBMask;
  163.     } else if ((c == 0) || ((c == 'd') && (string[1] != 0)
  164.         && (strncmp(string, "default", strlen(string)) == 0))) {
  165.     /*
  166.      * Use the default visual for the window's screen.
  167.      */
  168.  
  169.     if (colormapPtr != NULL) {
  170.         *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
  171.     }
  172.     *depthPtr = DefaultDepthOfScreen(Tk_Screen(tkwin));
  173.     return DefaultVisualOfScreen(Tk_Screen(tkwin));
  174.     } else {
  175.     /*
  176.      * Parse the string into a class name (or "best") optionally
  177.      * followed by whitespace and a depth.
  178.      */
  179.  
  180.     for (p = string; *p != 0; p++) {
  181.         if (isspace(UCHAR(*p)) || isdigit(UCHAR(*p))) {
  182.         break;
  183.         }
  184.     }
  185.     length = p - string;
  186.     template.class = -1;
  187.     for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) {
  188.         if ((dictPtr->name[0] == c) && (length >= dictPtr->minLength)
  189.             && (strncmp(string, dictPtr->name,
  190.             (size_t) length) == 0)) {
  191.         template.class = dictPtr->class;
  192.         break;
  193.         }
  194.     }
  195.     if (template.class == -1) {
  196.         Tcl_AppendResult(interp, "unknown or ambiguous visual name \"",
  197.             string, "\": class must be ", (char *) NULL);
  198.         for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) {
  199.         Tcl_AppendResult(interp, dictPtr->name, ", ", (char *) NULL);
  200.         }
  201.         Tcl_AppendResult(interp, "or default", (char *) NULL);
  202.         return NULL;
  203.     }
  204.     while (isspace(UCHAR(*p))) {
  205.         p++;
  206.     }
  207.     if (*p == 0) {
  208.         template.depth = 10000;
  209.     } else {
  210.         if (Tcl_GetInt(interp, p, &template.depth) != TCL_OK) {
  211.         return NULL;
  212.         }
  213.     }
  214.     if (c == 'b') {
  215.         mask = 0;
  216.     } else {
  217.         mask = VisualClassMask;
  218.     }
  219.     }
  220.  
  221.     /*
  222.      * Find all visuals that match the template we've just created,
  223.      * and return an error if there are none that match.
  224.      */
  225.  
  226.     template.screen = Tk_ScreenNumber(tkwin);
  227.     mask |= VisualScreenMask;
  228.     visInfoList = XGetVisualInfo(Tk_Display(tkwin), mask, &template,
  229.         &numVisuals);
  230.     if (visInfoList == NULL) {
  231.     interp->result = "couldn't find an appropriate visual";
  232.     return NULL;
  233.     }
  234.  
  235.     /*
  236.      * Search through the visuals that were returned to find the best
  237.      * one.  The choice is based on the following criteria, in decreasing
  238.      * order of importance:
  239.      *
  240.      * 1. Depth: choose a visual with exactly the desired depth,
  241.      *      else one with more bits than requested but as few bits
  242.      *      as possible, else one with fewer bits but as many as
  243.      *    possible.
  244.      * 2. Class: some visual classes are more desirable than others;
  245.      *    pick the visual with the most desirable class.
  246.      * 3. Default: the default visual for the screen gets preference
  247.      *    over other visuals, all else being equal.
  248.      */
  249.  
  250.     bestPrio = 0;
  251.     bestPtr = NULL;
  252.     for (i = 0; i < numVisuals; i++) {
  253.     switch (visInfoList[i].class) {
  254.         case DirectColor:    prio = 5; break;
  255.         case GrayScale:    prio = 1; break;
  256.         case PseudoColor:    prio = 7; break;
  257.         case StaticColor:    prio = 3; break;
  258.         case StaticGray:    prio = 1; break;
  259.         case TrueColor:    prio = 5; break;
  260.         default:        prio = 0; break;
  261.     }
  262.     if (visInfoList[i].visual
  263.         == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
  264.         prio++;
  265.     }
  266.     if (bestPtr == NULL) {
  267.         goto newBest;
  268.     }
  269.     if (visInfoList[i].depth < bestPtr->depth) {
  270.         if (visInfoList[i].depth >= template.depth) {
  271.         goto newBest;
  272.         }
  273.     } else if (visInfoList[i].depth > bestPtr->depth) {
  274.         if (bestPtr->depth < template.depth) {
  275.         goto newBest;
  276.         }
  277.     } else {
  278.         if (prio > bestPrio) {
  279.         goto newBest;
  280.         }
  281.     }
  282.     continue;
  283.  
  284.     newBest:
  285.     bestPtr = &visInfoList[i];
  286.     bestPrio = prio;
  287.     }
  288.     *depthPtr = bestPtr->depth;
  289.     visual = bestPtr->visual;
  290.     XFree((char *) visInfoList);
  291.  
  292.     /*
  293.      * If we need to find a colormap for this visual, do it now.
  294.      * If the visual is the default visual for the screen, then
  295.      * use the default colormap.  Otherwise search for an existing
  296.      * colormap that's shareable.  If all else fails, create a new
  297.      * colormap.
  298.      */
  299.  
  300.     if (colormapPtr != NULL) {
  301.     if (visual == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
  302.         *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
  303.     } else {
  304.         for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  305.             cmapPtr = cmapPtr->nextPtr) {
  306.         if (cmapPtr->shareable && (cmapPtr->visual == visual)) {
  307.             *colormapPtr = cmapPtr->colormap;
  308.             cmapPtr->refCount += 1;
  309.             goto done;
  310.         }
  311.         }
  312.         cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap));
  313.         cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin),
  314.             RootWindowOfScreen(Tk_Screen(tkwin)), visual,
  315.             AllocNone);
  316.         cmapPtr->refCount = 1;
  317.         cmapPtr->shareable = 1;
  318.         cmapPtr->nextPtr = dispPtr->cmapPtr;
  319.         dispPtr->cmapPtr = cmapPtr;
  320.         *colormapPtr = cmapPtr->colormap;
  321.     }
  322.     }
  323.  
  324.     done:
  325.     return visual;
  326. }
  327.  
  328. /*
  329.  *----------------------------------------------------------------------
  330.  *
  331.  * Tk_GetColormap --
  332.  *
  333.  *    Given a string identifying a colormap, this procedure finds
  334.  *    an appropriate colormap.
  335.  *
  336.  * Results:
  337.  *    The return value is normally the X resource identifier for the
  338.  *    colormap.  If an error occurs, None is returned and an error
  339.  *    message is placed in interp->result.
  340.  *
  341.  * Side effects:
  342.  *    A reference count is incremented for the colormap, so
  343.  *    Tk_FreeColormap must eventually be called exactly once for
  344.  *    each call to Tk_GetColormap.
  345.  *
  346.  *----------------------------------------------------------------------
  347.  */
  348.  
  349. Colormap
  350. Tk_GetColormap(interp, tkwin, string)
  351.     Tcl_Interp *interp;            /* Interpreter to use for error
  352.                      * reporting. */
  353.     Tk_Window tkwin;            /* Window where colormap will be
  354.                      * used. */
  355.     char *string;            /* String that identifies colormap:
  356.                      * either "new" or the name of
  357.                      * another window. */
  358. {
  359.     Colormap colormap;
  360.     TkColormap *cmapPtr;
  361.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  362.     Tk_Window other;
  363.  
  364.     /*
  365.      * Allocate a new colormap, if that's what is wanted.
  366.      */
  367.  
  368.     if (strcmp(string, "new") == 0) {
  369.     cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap));
  370.     cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin),
  371.         RootWindowOfScreen(Tk_Screen(tkwin)), Tk_Visual(tkwin),
  372.         AllocNone);
  373.     cmapPtr->visual = Tk_Visual(tkwin);
  374.     cmapPtr->refCount = 1;
  375.     cmapPtr->shareable = 0;
  376.     cmapPtr->nextPtr = dispPtr->cmapPtr;
  377.     dispPtr->cmapPtr = cmapPtr;
  378.     return cmapPtr->colormap;
  379.     }
  380.  
  381.     /*
  382.      * Use a colormap from an existing window.  It must have the same
  383.      * visual as tkwin (which means, among other things, that the
  384.      * other window must be on the same screen).
  385.      */
  386.  
  387.     other = Tk_NameToWindow(interp, string, tkwin);
  388.     if (other == NULL) {
  389.     return None;
  390.     }
  391.     if (Tk_Screen(other) != Tk_Screen(tkwin)) {
  392.     Tcl_AppendResult(interp, "can't use colormap for ", string,
  393.         ": not on same screen", (char *) NULL);
  394.     return None;
  395.     }
  396.     if (Tk_Visual(other) != Tk_Visual(tkwin)) {
  397.     Tcl_AppendResult(interp, "can't use colormap for ", string,
  398.         ": incompatible visuals", (char *) NULL);
  399.     return None;
  400.     }
  401.     colormap = Tk_Colormap(other);
  402.  
  403.     /*
  404.      * If the colormap was a special one allocated by code in this file,
  405.      * increment its reference count.
  406.      */
  407.  
  408.     for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  409.         cmapPtr = cmapPtr->nextPtr) {
  410.     if (cmapPtr->colormap == colormap) {
  411.         cmapPtr->refCount += 1;
  412.     }
  413.     }
  414.     return colormap;
  415. }
  416.  
  417. /*
  418.  *----------------------------------------------------------------------
  419.  *
  420.  * Tk_FreeColormap --
  421.  *
  422.  *    This procedure is called to release a colormap that was
  423.  *    previously allocated by Tk_GetColormap.
  424.  *
  425.  * Results:
  426.  *    None.
  427.  *
  428.  * Side effects:
  429.  *    The colormap's reference count is decremented.  If this was the
  430.  *    last reference to the colormap, then the colormap is freed.
  431.  *
  432.  *----------------------------------------------------------------------
  433.  */
  434.  
  435. void
  436. Tk_FreeColormap(display, colormap)
  437.     Display *display;            /* Display for which colormap was
  438.                      * allocated. */
  439.     Colormap colormap;            /* Colormap that is no longer needed.
  440.                      * Must have been returned by previous
  441.                      * call to Tk_GetColormap. */
  442. {
  443.     TkDisplay *dispPtr;
  444.     TkColormap *cmapPtr, *prevPtr;
  445.  
  446.     /*
  447.      * Find Tk's information about the display, then see if this
  448.      * colormap is a non-default one (if it's a default one, there
  449.      * won't be an entry for it in the display's list).
  450.      */
  451.  
  452.     dispPtr = TkGetDisplay(display);
  453.     if (dispPtr == NULL) {
  454.     panic("unknown display passed to Tk_FreeColormap");
  455.     }
  456.     for (prevPtr = NULL, cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  457.         prevPtr = cmapPtr, cmapPtr = cmapPtr->nextPtr) {
  458.     if (cmapPtr->colormap == colormap) {
  459.         cmapPtr->refCount -= 1;
  460.         if (cmapPtr->refCount == 0) {
  461.         XFreeColormap(display, colormap);
  462.         if (prevPtr == NULL) {
  463.             dispPtr->cmapPtr = cmapPtr->nextPtr;
  464.         } else {
  465.             prevPtr->nextPtr = cmapPtr->nextPtr;
  466.         }
  467.         ckfree((char *) cmapPtr);
  468.         }
  469.         return;
  470.     }
  471.     } 
  472. }
  473.